/* eslint-disable no-console */
/**
 * 缓存管理
 */
class CacheManager {

    constructor() {
        this.indexedDBVerison = 1;       // IndexedDB 版本
        this.dbConnections = new Map();  // 使用 Map 存储所有数据库连接
        this.activeDB = null;            // 当前活跃数据库引用
        this.config = window.__cacheConfig.getSetting('cacheGroups') || null;
        this.ready = this._initialize(); // 保存Promise引用
    }

    /**
     * 初始化缓存管理器
     */
    async _initialize() {
        try {
            await this.initStorages();
            // console.debug('[cacheManager] 初始化完成');
        } catch (error) {
            console.error('[cacheManager] 初始化失败：', error);
            throw error;
        }
    }

    /**
     * 初始化IndexedDB数据库连接
     * @param {string} dbName - 需要连接的数据库名称
     * @param {string} storeName - 对象存储空间名称
     * @returns {Promise<void>} - 返回 Promise，成功时 resolve，失败时 reject
     */
    async _initIndexedDB(dbName, storeName) {
        // console.debug(`[indexedDB] 正在初始化数据库: ${dbName}/${storeName}`);
        if (!dbName || !storeName) {
            throw new Error('必须提供 dbName 和 storeName');
        }

        // 检查是否已存在该数据库的连接，避免重复初始化
        if (this.dbConnections[dbName]) return;

        return new Promise((resolve, reject) => {
             // 打开/创建数据库，版本号为1
            const request = indexedDB.open(dbName, this.indexedDBVerison);

             // 数据库打开失败处理
            request.onerror = (event) => {
                console.error(`IndexedDB 连接失败: ${event.target.error}`);
                // 返回错误信息
                reject(event.target.error);
            };

             // 数据库打开成功处理
            request.onsuccess = (event) => {
                const db = event.target.result;
                // 缓存连接对象
                this.dbConnections.set(dbName, db);

                // 设置第一个初始化的数据库为默认活跃数据库
                if (!this.activeDB) {
                    this.activeDB = db;
                }
                // console.debug(`IndexedDB 连接成功: ${dbName}`);
                resolve(db);
            };

            // 数据库升级/初始化处理器
            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                // 检查对象存储空间是否存在，不存在则创建
                if (!db.objectStoreNames.contains(storeName)) {
                     // 创建对象存储空间，设置keyPath为'key'
                    db.createObjectStore(storeName, {
                        keyPath: 'id',
                        autoIncrement: false // 不使用自增ID
                    });
                    console.debug(`创建对象存储空间: ${storeName}`);
                }
            };
        });
    }

    /**
     * 初始化所有需要的存储
     */
    async initStorages() {
        // 使用Set实现自动去重，避免重复初始化相同数据库
        const dbConfigs = new Set();

        // 遍历所有缓存组配置
        Object.values(this.config).forEach(group => {
            // 遍历组内的所有存储项
            Object.values(group.items).forEach(item => {
                // 判断是否需要使用 IndexedDB 存储
                if (item.storage === 'indexedDB' || (!item.storage && group.defaultStorage === 'indexedDB')) {
                    // 生成标准化配置对象并序列化后存入Set去重
                    dbConfigs.add(JSON.stringify({
                        // 优先使用 item 级别的 dbName，回退到 group 级别的 dbName
                        dbName: item.dbName || group.dbName,
                        // 必须指定storeName
                        storeName: item.storeName
                    }));
                }
            });
        });

        // 初始化所有去重后的数据库配置
        for (const configStr of dbConfigs) {
            const {dbName, storeName} = JSON.parse(configStr);
            try {
                await this._initIndexedDB(dbName, storeName);
                // console.debug(`[indexedDB] 成功初始化: ${dbName}/${storeName}`);
            } catch (error) {
                console.error(`初始化 IndexedDB 失败: ${dbName}/${storeName}`, error);  // 记录完整错误
                throw new Error(`Failed to initialize ${dbName}/${storeName}`);        // 抛出简化错误
            }
        }
    }

    /**
    * 获取数据库实例
    * @param {string} [dbName] - 可选数据库名称
    * @returns {IDBDatabase|null} 数据库实例或 null
    */
    getDB(dbName) {
        if (!dbName) throw new Error('必须指定数据库名称');
        const db = this.dbConnections.get(dbName);
        if (!db) throw new Error(`数据库 ${dbName} 未连接`);

        return db;
    }

    /**
     * 获取完整缓存配置
     * @param {string} group - 组名
     * @param {string} item - 条目名
     * @returns {object} 合并后的配置
     */
    _getMergedConfig(group, item) {
        const groupConfig = this.config[group];
        if (!groupConfig) {
            throw new Error(`未知的缓存组: ${group}`);
        }

        const itemConfig = groupConfig.items[item];
        if (!itemConfig) {
            throw new Error(`未知的缓存条目: ${group}.${item}`);
        }

        return {
            key: itemConfig.key,
            storage: itemConfig.storage || groupConfig.defaultStorage,
            ttl: itemConfig.ttl,
            ttlUnit: itemConfig.ttlUnit,
            dbName: itemConfig.dbName || groupConfig.dbName,
            storeName: itemConfig.storeName
        };
    }

    /**
     * 获取缓存值
     * @param {string} group - 组名
     * @param {string} item - 条目名
     * @returns {Promise<T>} 缓存值或 null
     */
    async getConfig(group, item) {
        const config = this._getMergedConfig(group, item);
        // 仅当使用 indexedDB 时才等待初始化
        if (config.storage === 'indexedDB') {
            await this.ready;
        }

        try {
            switch (config.storage) {
                case 'localStorage':
                    return this._getFromLocalStorage(config);
                case 'sessionStorage':
                    return this._getFromSessionStorage(config);
                case 'indexedDB':
                    return this._getFromIndexedDB(config);
                default:
                    throw new Error(`不支持的存储类型: ${config.storage}`);
            }
        } catch (error) {
            console.error(`获取缓存[${group}.${item}]失败:`, error);
            return null;
        }
    }

    /**
     * 设置缓存值
     * @param {string} group - 组名
     * @param {string} item - 条目名
     * @param {any} value - 要缓存的值
     * @returns {Promise<void>}
     */
    async setConfig(group, item, value) {
        const config = this._getMergedConfig(group, item);
        // 仅当使用 indexedDB 时才等待初始化
        if (config.storage === 'indexedDB') {
            await this.ready;
        }

        try {
            // 计算过期时间
            const ttlValue = () => {
                switch (config.ttlUnit) {
                    case 'seconds':
                        return config.ttl * 1000;
                    case 'minutes':
                        return config.ttl * 1000 * 60;
                    case 'hours':
                        return config.ttl * 1000 * 60 * 60;
                    case 'day':
                        return config.ttl * 1000 * 60 * 60 * 24;
                    case 'week':
                        return config.ttl * 1000 * 60 * 60 * 24 * 7;
                    case 'month':
                        return config.ttl * 1000 * 60 * 60 * 24 * 30;
                    case 'year':
                        return config.ttl * 1000 * 60 * 60 * 24 * 365;
                    default:
                        return 0;
                }
            }

            const currentTime = Date.now();
            const cacheData = {
                value,
                timestamp: currentTime,
                expires: config.ttl ? currentTime + ttlValue() : null
            };

            switch (config.storage) {
                case 'localStorage':
                    this._setToLocalStorage(config, cacheData);
                    break;
                case 'sessionStorage':
                    this._setToSessionStorage(config, cacheData);
                    break;
                case 'indexedDB':
                    await this._setToIndexedDB(config, cacheData);
                    break;
                default:
                    throw new Error(`不支持的存储类型: ${config.storage}`);
            }
        } catch (error) {
            console.error(`设置缓存[${group}.${item}]失败:`, error);
        }
    }

    /**
     * 清除指定缓存（可排除特定key）
     * @param {string} cacheName - 缓存配置名称
     * @param {string[]} [excludeKeys=[]] - 需要排除的key数组
     * @returns {Promise<void>}
     */
    async clearConfig(cacheName, excludeKeys) {
        const config = this.config[cacheName];

        if (!config) {
            console.warn(`未找到配置: ${cacheName}`);
            return;
        }

        // 检查排除 key 是否有效
        if (excludeKeys && !Array.isArray(excludeKeys)) {
            throw new TypeError('excludeKeys 必须是数组');
        }

        // 仅当使用 indexedDB 时才等待初始化
        if (config.defaultStorage === 'indexedDB') {
            await this.ready;
        }

        try {
            switch (config.defaultStorage) {
                case 'localStorage':
                    this._clearLocalStorage(config, excludeKeys);
                    break;
                case 'sessionStorage':
                    this._clearSessionStorage(config, excludeKeys);
                    break;
                case 'indexedDB':
                    await this._clearIndexedDB(config, excludeKeys);
                    break;
                default:
                    throw new Error(`不支持的存储类型: '${config.storage}'`);
            }
        } catch (error) {
            console.error(`清除缓存[${cacheName}]失败:`, error);
            throw error; // 重新抛出错误以便上层捕获
        }
    }

    // 私有方法
    _getFromLocalStorage(config) {
        const item = localStorage.getItem(config.key);
        if (!item) return null;

        const data = JSON.parse(item);
        if (data.expires && Date.now() > data.expires) {
            localStorage.removeItem(config.key);
            return null;
        }
        if (!data.value) {
            console.error(`[localStorage] ${config.key} 无 value 属性`)
            return null;
        }
        return data.value;
    }

    _setToLocalStorage(config, data) {
        localStorage.setItem(config.key, JSON.stringify(data));
    }

    _getFromSessionStorage(config) {
        const item = sessionStorage.getItem(config.key);
        if (!item) return null;

        const data = JSON.parse(item);
        if (data.expires && Date.now() > data.expires) {
            sessionStorage.removeItem(config.key);
            return null;
        }
        if (!data.value) {
            console.error(`[sessionStorage] ${config.key} 无 value 属性`)
            return null;
        }
        return data.value;
    }

    _setToSessionStorage(config, data) {
        sessionStorage.setItem(config.key, JSON.stringify(data));
    }

    async _getFromIndexedDB(config) {
        const db = this.getDB(config.dbName);
        if (!db) throw new Error(`数据库 ${config.dbName} 未连接`);

        return new Promise((resolve, reject) => {
            const transaction = this.activeDB.transaction(config.storeName, 'readonly');
            const store = transaction.objectStore(config.storeName);
            const request = store.get(config.key);

            request.onsuccess = (event) => {
                const data = event.target.result;
                if (!data) {
                    resolve(null);
                } else if (data.expires && Date.now() > data.expires) {
                    this._clearIndexedDB(config);
                    resolve(null);
                } else {
                    resolve(data.value);
                }
            };

            request.onerror = () => reject(new Error(`[IndexedDB] 读取失败: ${request.error}`));
        });
    }

    async _setToIndexedDB(config, data) {
        const db = this.getDB(config.dbName);
        if (!db) throw new Error(`数据库 ${config.dbName} 未连接`);

        return new Promise((resolve, reject) => {
            const transaction = this.activeDB.transaction(config.storeName, 'readwrite');
            const store = transaction.objectStore(config.storeName);
            const request = store.put({id: config.key, ...data});

            request.onsuccess = () => resolve();
            request.onerror = () => reject(new Error(`[IndexedDB] 保存失败: ${request.error}`));
        });
    }

    /**
     * 验证缓存项是否有效
     * @param {object} config - 缓存项
     * @param {string} [storageType] - 存储类型
     * @returns {boolean} 是否有效
     */
    isValidCacheItem(config, storageType = 'localStorage') {
        if (!config?.items || typeof config?.items !== 'object') {
            console.warn(`[${storageType}] 存在无效的缓存项:`, config);
            return false;
        }

        Object.values(config.items).forEach((item) => {
            if (!item?.key || typeof item.key !== 'string') {
                console.warn(`[${storageType}] 缺少有效的key属性:`, item);
                return false;
            }
        });

        return true;
    }

    _clearLocalStorage(config, excludeKeys = []) {
        if (!this.isValidCacheItem(config, 'localStorage')) return;

        Object.values(config.items).forEach((item) => {
            if (excludeKeys.includes(item.key)) {
                console.debug(`[localStorage] skipped key: ${item.key}`);
                return;
            }
            localStorage.removeItem(item.key);
            if (localStorage.getItem(item.key) === null) {
                console.debug(`[localStorage] 清除key成功: ${item.key}`);
            } else {
                console.debug(`[localStorage] 清除key失败: ${item.key}`);
            }
        })
    }

    _clearSessionStorage(config, excludeKeys = []) {
        if (!this.isValidCacheItem(config, 'sessionStorage')) return;

        Object.values(config.items).forEach((item) => {
            if (excludeKeys.includes(item.key)) {
                console.debug(`[sessionStorage] skipped key: ${item.key}`);
                return;
            }
            sessionStorage.removeItem(item.key);
            if (sessionStorage.getItem(item.key) === null) {
                console.debug(`[sessionStorage] 清除key成功: ${item.key}`);
            } else {
                console.debug(`[sessionStorage] 清除key失败: ${item.key}`);
            }
        })
    }

    async _clearIndexedDB(config,  excludeKeys = []) {
        if (!this.isValidCacheItem(config, 'indexedDB')) return;

        Object.values(config.items).forEach((item) => {
            if (excludeKeys.includes(item.key)) {
                console.debug(`[IndexedDB] skipped key: ${item.key}`);
                return;
            }

            const db = this.getDB(config.dbName);
            if (!db) throw new Error(`数据库 ${config.dbName} 未连接`);

            return new Promise((resolve, reject) => {
                const transaction = this.activeDB.transaction(item.storeName, 'readwrite');
                const store = transaction.objectStore(item.storeName);
                const request = store.delete(item.key);

                request.onsuccess = () => {
                    // TODO 暂未检查删除是否成功
                    console.debug(`[IndexedDB] 清除key成功: ${item.key}`);
                    resolve();
                };
                request.onerror = (event) => {
                    console.error(`[IndexedDB] 删除key失败: ${item.key} - `, event.target.error);
                    reject(event.target.error)
                };
            });
        });
    }
}

// 安全暴露接口
const manager = new CacheManager();
Object.defineProperty(window, '__cacheManager', {
    value: manager,
    writable: false,      // 防止替换实例
    configurable: false,  // 防止重新定义
    enumerable: false
});